﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;

namespace Reviewer.Utilities.Drawing
{
    /// <summary>
    /// Image Dimensions
    /// </summary>
    public enum ImageDimension
    {
        /// <summary>
        /// Width dimension
        /// </summary>
        Width,
        /// <summary>
        /// Height dimension
        /// </summary>
        Height
    }

    /// <summary>
    /// Image anchor positions
    /// </summary>
    public enum ImageAnchorPosition
    {
        /// <summary>
        /// Top position
        /// </summary>
        Top,
        /// <summary>
        /// Center position
        /// </summary>
        Center,
        /// <summary>
        /// Botton position
        /// </summary>
        Bottom,
        /// <summary>
        /// Left position
        /// </summary>
        Left,
        /// <summary>
        /// Right position
        /// </summary>
        Right
    }

    /// <summary>
    /// Image helper utility
    /// </summary>
    public static class ImageUtility
    {
        /// <summary>
        /// Scales the image.
        /// </summary>
        /// <param name="original">The original.</param>
        /// <param name="percentage">The percentage.</param>
        /// <returns></returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
        public static Image ScaleImage(Image original, int percentage)
        {
            if (original == null)
            {
                throw new ArgumentNullException("original");
            }

            float percent = ((float)percentage / 100);

            int sourceWidth = original.Width;
            int sourceHeight = original.Height;
            int sourceX = 0;
            int sourceY = 0;

            int destX = 0;
            int destY = 0;
            int destWidth = (int)(sourceWidth * percent);
            int destHeight = (int)(sourceHeight * percent);

            Bitmap newImage = new Bitmap(destWidth, destHeight, PixelFormat.Format24bppRgb);
            newImage.SetResolution(original.HorizontalResolution, original.VerticalResolution);

            using (Graphics graphics = Graphics.FromImage(newImage))
            {
                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

                graphics.DrawImage(original,
                    new Rectangle(destX, destY, destWidth, destHeight),
                    new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
                    GraphicsUnit.Pixel);
            }

            return newImage;
        }

        /// <summary>
        /// Scales the image with proportions.
        /// </summary>
        /// <param name="original">The original.</param>
        /// <param name="maxWith">The max with.</param>
        /// <param name="maxHeight">Height of the max.</param>
        /// <returns></returns>
        public static Image ScaleImageWithProportions(Image original, int maxWith, int maxHeight)
        {
            if (original == null)
            {
                throw new ArgumentNullException("original");
            }

            int widthRatio = maxWith / original.Size.Width;
            int heightRatio = maxHeight / original.Size.Height;

            if (widthRatio < heightRatio)
            {
                return ScaleImageWithProportions(original, maxWith, ImageDimension.Width);
            }
            else
            {
                return ScaleImageWithProportions(original, maxHeight, ImageDimension.Height);
            }
        }

        /// <summary>
        /// Scales the image with proportions.
        /// </summary>
        /// <param name="original">The original.</param>
        /// <param name="size">The size.</param>
        /// <param name="dimensions">The dimensions.</param>
        /// <returns></returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
        public static Image ScaleImageWithProportions(Image original, int size, ImageDimension dimensions)
        {
            if (original == null)
            {
                throw new ArgumentNullException("original");
            }

            int sourceWidth = original.Width;
            int sourceHeight = original.Height;
            int sourceX = 0;
            int sourceY = 0;
            int destX = 0;
            int destY = 0;
            float nPercent = 0;

            switch (dimensions)
            {
                case ImageDimension.Width:
                    nPercent = ((float)size / (float)sourceWidth);
                    break;
                default:
                    nPercent = ((float)size / (float)sourceHeight);
                    break;
            }

            int destWidth = (int)(sourceWidth * nPercent);
            int destHeight = (int)(sourceHeight * nPercent);

            Bitmap newImage = new Bitmap(destWidth, destHeight, PixelFormat.Format24bppRgb);
            newImage.SetResolution(original.HorizontalResolution, original.VerticalResolution);

            using (Graphics graphics = Graphics.FromImage(newImage))
            {
                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

                graphics.DrawImage(original,
                new Rectangle(destX, destY, destWidth, destHeight),
                new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
                GraphicsUnit.Pixel);
            }

            return newImage;
        }

        /// <summary>
        /// Resizes the image.
        /// </summary>
        /// <param name="original">The original.</param>
        /// <param name="width">The width.</param>
        /// <param name="height">The height.</param>
        /// <returns></returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
        public static Image ResizeImage(Image original, int width, int height)
        {
            if (original == null)
            {
                throw new ArgumentNullException("original");
            }

            int sourceWidth = original.Width;
            int sourceHeight = original.Height;
            int sourceX = 0;
            int sourceY = 0;
            int destX = 0;
            int destY = 0;

            float percent = 0;
            float percentWidth = 0;
            float percentHeight = 0;

            percentWidth = ((float)width / (float)sourceWidth);
            percentHeight = ((float)height / (float)sourceHeight);

            //if we have to pad the height pad both the top and the bottom
            //with the difference between the scaled height and the desired height
            if (percentHeight < percentWidth)
            {
                percent = percentHeight;
                destX = (int)((width - (sourceWidth * percent)) / 2);
            }
            else
            {
                percent = percentWidth;
                destY = (int)((height - (sourceHeight * percent)) / 2);
            }

            int destWidth = (int)(sourceWidth * percent);
            int destHeight = (int)(sourceHeight * percent);

            Bitmap newImage = new Bitmap(width, height, PixelFormat.Format24bppRgb);
            newImage.SetResolution(original.HorizontalResolution, original.VerticalResolution);

            using (Graphics graphics = Graphics.FromImage(newImage))
            {
                graphics.Clear(Color.Red);
                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

                graphics.DrawImage(original,
                    new Rectangle(destX, destY, destWidth, destHeight),
                    new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
                    GraphicsUnit.Pixel);
            }

            return newImage;
        }

        /// <summary>
        /// Crops the image.
        /// </summary>
        /// <param name="original">The original.</param>
        /// <param name="width">The width.</param>
        /// <param name="height">The height.</param>
        /// <param name="anchor">The anchor.</param>
        /// <returns></returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
        public static Image CropImage(Image original, int width, int height, ImageAnchorPosition anchor)
        {
            if (original == null)
            {
                throw new ArgumentNullException("original");
            }

            int sourceWidth = original.Width;
            int sourceHeight = original.Height;
            int sourceX = 0;
            int sourceY = 0;
            int destX = 0;
            int destY = 0;

            float percent = 0;
            float percentWidth = 0;
            float percentHeight = 0;

            percentWidth = ((float)width / (float)sourceWidth);
            percentHeight = ((float)height / (float)sourceHeight);

            if (percentHeight < percentWidth)
            {
                percent = percentWidth;
                switch (anchor)
                {
                    case ImageAnchorPosition.Top:
                        destY = 0;
                        break;
                    case ImageAnchorPosition.Bottom:
                        destY = (int)(height - (sourceHeight * percent));
                        break;
                    default:
                        destY = (int)((height - (sourceHeight * percent)) / 2);
                        break;
                }
            }
            else
            {
                percent = percentHeight;
                switch (anchor)
                {
                    case ImageAnchorPosition.Left:
                        destX = 0;
                        break;
                    case ImageAnchorPosition.Right:
                        destX = (int)(width - (sourceWidth * percent));
                        break;
                    default:
                        destX = (int)((width - (sourceWidth * percent)) / 2);
                        break;
                }
            }

            int destWidth = (int)(sourceWidth * percent);
            int destHeight = (int)(sourceHeight * percent);

            Bitmap bmPhoto = new Bitmap(width, height, PixelFormat.Format24bppRgb);
            bmPhoto.SetResolution(original.HorizontalResolution, original.VerticalResolution);

            Graphics grPhoto = Graphics.FromImage(bmPhoto);
            grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;

            grPhoto.DrawImage(original,
                new Rectangle(destX, destY, destWidth, destHeight),
                new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
                GraphicsUnit.Pixel);

            grPhoto.Dispose();
            return bmPhoto;
        }
    }
}
